package model.datastructure;


public class BlockType2D extends AbstractBlockType {

	private final char emptyChar = 0;
	
	private int[][][] structure;
	private Dimension2D[] dimensions;
	private BlockSurface2D[] blockSurfaces;

	public int getWidth( int rotation ) {
		return structure[rotation][0].length;
	}

	public int getHeight( int rotation ) {
		return structure[rotation].length;
	}

	public int getNumberOfRotations() {
		return rotations;
	}

	public BlockType2D( int[][] baseStructure ) {
		
		/* create all rotations */
		structure = new int[4][baseStructure.length][baseStructure[0].length];
		structure[0] = baseStructure;
		structure[1] = rotateRight( structure[0] );
		structure[2] = rotateRight( structure[1] );
		structure[3] = rotateRight( structure[2] );

		/* if some rotations turn out to be the same, remove then */
		if( rotationEquals( structure[0], structure[1] ) ) {
			int[][][] actualBlock = new int[1][baseStructure.length][baseStructure[0].length];
			actualBlock[0] = structure[0];
			structure = actualBlock;
		} else if( rotationEquals( structure[0], structure[2] ) ) {
			int[][][] actualBlock = new int[2][baseStructure.length][baseStructure[0].length];
			actualBlock[0] = structure[0];
			actualBlock[1] = structure[1];
			structure = actualBlock;
		}
		
		/* Set the number of rotations */
		rotations = structure.length;
		
		/* Create the dimensions and the blocksurfaces */
		dimensions = new Dimension2D[rotations];
		blockSurfaces = new BlockSurface2D[rotations];
		
		for(int i = rotations - 1; i >= 0; i--) {
			int width = structure[i].length;
			int height = structure[i][0].length;
			dimensions[i] = new Dimension2D(width, height);
			Dimension1D dimension1D = new Dimension1D(width); 
			blockSurfaces[i] = new BlockSurface2D(this, dimension1D, i);
		}
	}
	
	public char getEmptyChar() {
		return emptyChar;
	}

	private boolean rotationEquals( int[][] first, int[][] second ) {
		boolean same = first.length == second.length && first[0].length == second[0].length;
		int i = 0;
		while( i < first.length && same ) {
			int j = 0;
			while( same && j < first[i].length ) {
				same = first[i][j] == second[i][j];
				j ++ ;
			}
			i ++ ;
		}
		return same;
	}

	private int[][] rotateRight( int[][] original ) {
		int originalX = original.length;
		int originalY = original[0].length;
		int[][] result = new int[originalY][originalX];
		for( int x = 0; x < originalX; x ++ ) {
			for( int y = 0; y < originalY; y ++ ) {
				result[y][originalX - 1 - x] = original[x][y];
			}
		}
		return result;
	}

	/**
	 * Returns the character at the given x and y
	 * 
	 * @param x
	 *            the desired x
	 * @param y
	 *            the desired y
	 * @return the character
	 */
	public char getCharAt( int x, int y, int rotation ) {
		assert x >= 0;
		assert x < getDimension( rotation ).getWidth();
		assert y >= 0;
		assert y < getDimension( rotation ).getHeight();
		return ( char ) structure[rotation][x][y];
	}

	@Override
	public Dimension2D getDimension( int rotation ) {
		return dimensions[rotation];
	}

	@Override
	public BlockSurface2D getSurface( int rotation ) {
		return blockSurfaces[rotation];
	}

	public String toString() {
		/* The return String */
		String blockString = "";
		for (int rot = 0 ; rot < structure.length; rot++){
			blockString += ("Rotation " + (rot) + ": \n");
			int yLength = structure[rot][0].length;
			for (int y = 0; y < yLength; y++){
				int xLength = structure[rot].length;
				for (int x = 0; x < xLength; x++){
					blockString += "" + structure[rot][x][yLength-1-y];
				}
				blockString += "\n";
			}
			blockString += "--------------------";
			if (rot < structure.length-1){
				blockString += "\n";
			}
		}
		return blockString;
	}
}